import {
  BadRequestException,
  HttpException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { CreateUserDto } from './dto/create-user.dto';
import { UpdateUserDto } from './dto/update-user.dto';
import { PrismaService } from 'nestjs-prisma';
import { NumberToBool } from '../../common/utils/util';
import { decode, encryption } from '../../common/utils/crypto';
import { QueryPageDto } from '../../common/dto/query.page.dto';
import { QueryUserDto } from './dto/query-user.dto';
import { PageDto } from '../../common/dto/page.dto';
import { Prisma } from '@prisma/client';
import { GetSkit, GetSort } from '../../common/utils/query';
import { ResetUserDto } from './dto/reset-user.dto';
import { UpdateUserInfoDto } from './dto/update-user-info.dto';
import { ResetUserPasswordDto } from './dto/reset-user-password.dto';

@Injectable()
export class UserService {
  logger = new Logger(UserService.name);
  constructor(private prisma: PrismaService) {}
  async create(createUserDto: CreateUserDto) {
    const { password, iv, key } = encryption(createUserDto.password);
    return await this.prisma.user.create({
      data: {
        ...createUserDto,
        password,
        iv,
        key,
      },
    });
  }

  async findByPage(query: QueryPageDto<QueryUserDto>) {
    const result = new PageDto(query);
    const where: Prisma.userWhereInput = {
      name: {
        contains: query.model?.name || undefined,
      },
      username: {
        contains: query.model?.username || undefined,
      },
      disabled: NumberToBool(query.model?.disabled),
      mobile: {
        contains: query.model?.mobile || undefined,
      },
    };
    const skip = GetSkit(query);
    const order = GetSort(query);
    const record = this.prisma.user.findMany({
      where: where,
      ...skip,
      ...order,
    });

    const total = this.prisma.user.count({ where });

    const users = await this.prisma.$transaction([record, total]).catch((e) => {
      this.logger.error(e.message);
      throw new HttpException(e.message, HttpStatus.BAD_REQUEST);
    });
    result.record = users[0].map((item) => {
      delete item.password;
      delete item.iv;
      delete item.key;
      return item;
    });
    result.total = users[1];

    return result;
  }

  async findOne(id: string) {
    const result: any = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });
    delete result.password;
    delete result.iv;
    delete result.key;
    return result;
  }

  update(id: string, updateUserDto: UpdateUserDto) {
    return this.prisma.user.update({
      where: {
        id,
      },
      data: {
        ...updateUserDto,
      },
    });
  }

  async remove(id: string) {
    return this.prisma.user.delete({
      where: {
        id,
      },
    });
  }

  resetPassword(id: string, form: ResetUserDto) {
    const { iv, password, key } = encryption(form.password);
    return this.prisma.user.update({
      where: { id },
      data: {
        iv,
        password,
        key,
      },
    });
  }

  async newPassword(id: string, form: ResetUserPasswordDto) {
    const { iv, password, key } = encryption(form.newPassword);
    const user = await this.prisma.user.findUnique({
      where: {
        id,
      },
    });
    const oldPassword = decode(user.password, user.key, user.iv);
    if (oldPassword != form.password) {
      throw new BadRequestException('旧密码错误！');
    }
    return this.prisma.user.update({
      where: { id },
      data: {
        iv,
        password,
        key,
      },
    });
  }

  async updateUserInfo(userId: string, userInfo: UpdateUserInfoDto) {
    await this.prisma.user.update({
      where: {
        id: userId,
      },
      data: userInfo,
    });
  }

  findAll() {
    return this.prisma.user.findMany({
      where: {
        disabled: false,
      },
      select: {
        id: true,
        name: true,
        username: true,
      },
    });
  }
}
